package org.xiaov.framework.util;

import cn.hutool.core.util.StrUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.xiaov.framework.component.SpringContext;
import org.xiaov.framework.component.properties.TokenProperties;
import org.xiaov.framework.exception.BizException;

import java.util.Date;
import java.util.Map;

/**
 * <p>
 * 描述：
 * </p>
 *
 * @author xiaovcloud
 * @since 2021/10/6 12:28
 */
public class TokenUtils {

    private static final TokenProperties TOKEN_PROPERTIES =
            SpringContext.getBean(TokenProperties.class);

    /**
     * 从token中获取claim
     *
     * @param token token
     * @return claim
     */
    public static Claims parseToken(String token) {
        try {
            return Jwts.parser()
                    .setSigningKey(TOKEN_PROPERTIES.getSecretKey())
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            throw new BizException("登录信息失效，请重新登录", e);
        }
    }

    /**
     * 从token中获取特定的值
     *
     * @param token token
     * @param key   键
     * @param clazz 返回的类型
     * @param <T>   泛型
     * @return 值
     */
    public static <T> T parseToken(String token, String key, Class<T> clazz) {
        Claims claims = parseToken(token);
        return claims.get(key, clazz);
    }

    /**
     * 获取token的过期时间
     *
     * @param token token
     * @return 过期时间
     */
    public static Date getExpirationDateFromToken(String token) {
        return parseToken(token).getExpiration();
    }

    /**
     * 判断token是否过期
     *
     * @param token token
     * @return 已过期返回true，未过期返回false
     */
    private static Boolean isTokenExpired(String token) {
        Date expiration = getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }

    /**
     * 计算token的过期时间
     *
     * @return 过期时间
     */
    private static Date getExpirationTime() {
        return new Date(System.currentTimeMillis() + TOKEN_PROPERTIES.getExpireTime() * 1000);
    }

    /**
     * 为指定用户生成token
     *
     * @param claims 用户信息
     * @return token
     */
    public static String buildToken(Map<String, Object> claims) {
        if (StrUtil.isBlank(TOKEN_PROPERTIES.getSecretKey())) {
            throw new BizException("未指定token私钥key");
        }
        //获取过期时间
        Date expirationTime = getExpirationTime();

        JwtBuilder builder = Jwts.builder()
                .setIssuedAt(new Date())
                .setExpiration(expirationTime)
                .setClaims(claims)
                .signWith(TOKEN_PROPERTIES.getSignature(), TOKEN_PROPERTIES.getSecretKey());
        //设置过期时间
        if (TOKEN_PROPERTIES.getExpireTime() > 0) {
            builder.setExpiration(expirationTime);
        }

        return builder.compact();
    }

    /**
     * 判断token是否非法
     *
     * @param token token
     * @return 未过期返回true，否则返回false
     */
    public static Boolean validateToken(String token) {
        return !isTokenExpired(token);
    }


}
